package com.wumart.scaffold.web.service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author wangwc@wumart.com
 * @version v1.0.0
 * @date 2021/2/25 11:55
 */
public interface SpringBeanGateway {
    /**
     * key 必须继承NameMark
     */
    interface NameMark {

    }

    /**
     * 实例的标志,用于静态内部类实例缓存中key{@link LazyHolder.INSTANCE}
     * @return
     */
    NameMark name();

    /**
     * 静态内部类，缓存获取service实例集合
     */
    static class LazyHolder {
        /**
         * 缓存实例
         */
        private static final Map<Class<?>, Map<NameMark, Object>> INSTANCE = new ConcurrentHashMap<>();

        /**
         * put方法
         * @param superClazz
         * @param name
         * @param obj
         */
        private static void put(Class<?> superClazz, NameMark name, Object obj) {
            Map<NameMark, Object> value = INSTANCE.computeIfAbsent(superClazz, k -> new HashMap<>());
            value.put(name, obj);
        }

        /**
         * 实例的get方法
         * @param superClazz
         * @param name
         * @param <T>
         * @return
         */
        private static <T> T get(Class<T> superClazz, NameMark name) {
            Map<NameMark, Object> value = INSTANCE.get(superClazz);
            if (value == null) {
                return null;
            }
            return (T) value.get(name);
        }

        /**
         * 初始化加载，懒加载模式
         */
        static {
            Map<String, SpringBeanGateway> impl = SpringBeanUtil.getImplInstance(SpringBeanGateway.class);
            for (Map.Entry<String, SpringBeanGateway> e : impl.entrySet()) {
                SpringBeanGateway bean = e.getValue();
                NameMark key = bean.name();
                Class<?> clazz = bean.getClass();
                Class<?> superClazz = clazz.getSuperclass();
                /**
                 *  父类非Object对象
                 */
                if (!superClazz.equals(Object.class)){
                    put(superClazz, key, bean);
                }
                /**
                 * 接口
                 */
                Class<?>[] interfaces = clazz.getInterfaces();
                for (Class<?> i:interfaces) {
                    put(i, key, bean);
                }
            }
        }
    }

    /**
     * 对外提供的方法
     * @param clazz
     * @param name
     * @param <T>
     * @return
     */
    static <T> T getInstance(Class<T> clazz, NameMark name) {
        T value = LazyHolder.get(clazz, name);
        return value;
    }
}
